/*
 * polymer_list.h
 *
 *  Created on: Oct 4, 2012
 *      Author: hammer
 */

class Dim_log_line {
public:
	long long int att,succ;
	double R2,R4;
	void init();
	Dim_log_line();
	void print();
	void print(ofstream& out_file);
};

Dim_log_line::Dim_log_line() {
	att=0; succ=0; R2=0; R4=0;
}

void Dim_log_line::print() {
	cout << att << "\t" << succ << "\t" << R2 << "\t" << R4 << "\n";
}

void Dim_log_line::print(ofstream& out_file) {
	out_file << att << "\t" << succ << "\t" << R2 << "\t" << R4 << "\n";
}

class Polymer_list {
	vector< vector<float> > list;
	float sphere_r;
	int N_list,N_poly,DIM;
public:
	Polymer_list(int n_list,int n_poly,int d,float s);
	void make_list();
	void make_list(ofstream&);
	void add_polymer(Polymer);
	void read_list(ifstream&);
	Polymer get_polymer(int n);
	Polymer dimerization(int level,Hash_table& table1);
	Polymer dimerization(int level,Hash_table& table1, Dim_log_line*  log);
	Polymer dimerization(int level);
	Polymer dimerization(int level,Dim_log_line* log);
};

Polymer_list::Polymer_list(int n_list,int n_poly,int d,float r) {
	DIM=d;
	N_list=n_list;
	N_poly=n_poly;
	sphere_r=r;
}

void Polymer_list::add_polymer(Polymer poly1) {
	int i;
	for (i=0;i<N_poly;i++) {
		list.push_back(poly1.get_pos(i));
	}
}

void Polymer_list::make_list() {
	Hash_table table1(N_poly,DIM);
	int count=0;
	Polymer poly1(N_poly,DIM);
	while (count<N_list) {
		poly1.make_random(1);
		if (table1.check_SA(poly1,sphere_r)) {
			add_polymer(poly1);
			count++;
		}
	}
}

void Polymer_list::make_list(ofstream& out_file) {
	Hash_table table1(N_poly,DIM);
	int count=0;
	Polymer poly1(N_poly,DIM);
	while (count<N_list) {
		poly1.make_random(1);
		if (table1.check_SA(poly1,sphere_r)) {
			add_polymer(poly1);
			poly1.print(out_file);
			count++;
		}
	}
}

void Polymer_list::read_list(ifstream& in_file) {
	int i,j;
	vector<float> pos;
	pos.resize(DIM);
	for (i=0;i<N_list*N_poly;i++) {
		for (j=0;j<DIM;j++) {
			in_file >> pos[j];
		}
		list.push_back(pos);
	}
}

Polymer Polymer_list::get_polymer(int n) {
	Polymer poly1;
	int i;
	for (i=n*N_poly;i<(n+1)*N_poly;i++) poly1.add_monomer(list[i]);
	return poly1;
}

Polymer Polymer_list::dimerization(int level,Hash_table& table1) {
	if (level==0) {
		return get_polymer(ran2_int(&idum,0,N_list-1));
	}
	else {
		Polymer poly1;
		Polymer poly2;
		Polymer poly3;
		bool check=0;
		while (check==0) {
			poly1=dimerization(level-1,table1);
			poly2=dimerization(level-1,table1);
			poly3=poly1+poly2;
			check=table1.check_SA(poly3,sphere_r);
		}
		return poly3;
	}
}

Polymer Polymer_list::dimerization(int level,Hash_table& table1,Dim_log_line* log) {
	if (level==0) {
		return get_polymer(ran2_int(&idum,0,N_list-1));
	}
	else {
		Polymer poly1;
		Polymer poly2;
		Polymer poly3;
		bool check=0;
		while (check==0) {
			log[level-1].att++;
			poly1=dimerization(level-1,table1,log);
			poly2=dimerization(level-1,table1,log);
			poly3=poly1+poly2;
			check=table1.check_SA(poly3,sphere_r);
		}
		log[level-1].succ++;
		log[level-1].R2 = log[level-1].R2 + poly3.R_EE();
		log[level-1].R4 = log[level-1].R4 + poly3.R_EE()*poly3.R_EE();
		return poly3;
	}
}

Polymer Polymer_list::dimerization(int level) {
	if (level==0) {
		return get_polymer(ran2_int(&idum,0,N_list-1));
	}
	else {
		Polymer poly1;
		Polymer poly2;
		Polymer poly3;
		bool check=0;
		while (check==0) {
			poly1=dimerization(level-1);
			poly2=dimerization(level-1);
			poly3=poly1+poly2;
			check=poly3.check_joining((poly3.get_length()-1)/2,sphere_r);
			//cout << "level: " << level << " success: " << check <<"\n";
		}
		return poly3;
	}
}

Polymer Polymer_list::dimerization(int level,Dim_log_line* log) {
	if (level==0) {
			return get_polymer(ran2_int(&idum,0,N_list-1));
		}
		else {
			Polymer poly1;
			Polymer poly2;
			Polymer poly3;
			bool check=0;
			while (check==0) {
				log[level-1].att++;
				poly1=dimerization(level-1,log);
				poly2=dimerization(level-1,log);
				poly3=poly1+poly2;
				check=poly3.check_joining((poly3.get_length()-1)/2,sphere_r);
			}
			log[level-1].succ++;
			log[level-1].R2 = log[level-1].R2 + poly3.R_EE();
			log[level-1].R4 = log[level-1].R4 + poly3.R_EE()*poly3.R_EE();
			return poly3;
		}
}

